iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
Software Development

從 Vibe Coding 到可維護專案:用 Hermes Agent 重讀 RoomRush Android 專題系列 第 12 篇

Day 12 | App 要查資料、改資料,Room DAO 負責哪一層?

  • 分享至 

  • xImage
  •  

前言:資料庫查詢、新增、更新、刪除在哪裡定義?

前一篇文章介紹了 ClassroomSchedule.kt 作為 RoomRush 的 Room Entity,負責定義 classroom_schedules 資料表的欄位結構。

有了資料表之後,下一個核心問題就是:App 該如何對這張資料表進行讀寫?

今天我們要深入探討的 ClassroomScheduleDao.kt,正是資料層主線中負責定義這些 SQL 操作介面的核心主角。


一開始我認為

起初,我其實不太確定這項檔案主要是做什麼用的,可能是我自己對 DAO 的概念不太熟悉。

後來查詢相關資料後,我才了解:在 Android 的現代資料庫架構中,所有對資料庫的 CRUD(新增、查詢、更新、刪除)操作,都不會直接寫在 Activity 或 ViewModel 裡,而是會統一封裝在 DAO(Data Access Object,資料存取物件) 中。


實際讀完後,ClassroomScheduleDao.kt 負責什麼

和 Hermes Agent 一起重讀檔案後,我理解ClassroomScheduleDao.kt是負責定義資料表的操作方法,例如查詢、新增、更新、刪除。

在 RoomRush 中,主要包含以下四大核心操作:

1. 取得所有課表

@Query("SELECT * FROM classroom_schedules ORDER BY classroom ASC")
fun getAll(): Flow<List<ClassroomSchedule>>
  • 技術細節:查詢全部教室課表,依 classroom 按教室名稱升冪排序,並用 Flow 回傳可被持續觀察的清單。

2. 新增、批次新增、更新、刪除

@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(schedule: ClassroomSchedule)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(schedules: List<ClassroomSchedule>)

@Update
suspend fun update(schedule: ClassroomSchedule)

@Delete
suspend fun delete(schedule: ClassroomSchedule)
  • insert:新增一筆,IGNORE 表示主鍵存在就忽略。
  • insertAll(schedules):批次新增多筆,REPLACE 表示主鍵存在就用新資料覆蓋舊資料。
  • @Update 更新已存在的一筆教室課表。
  • @Delete 刪除一筆教室課表。

3. 依大樓與樓層查詢

@Query("SELECT * FROM classroom_schedules WHERE classroom LIKE :buildingAndFloorPrefix ORDER BY classroom ASC")
suspend fun getSchedulesByBuildingAndFloor(buildingAndFloorPrefix: String): List<ClassroomSchedule>
  • 技術細節:使用 SQL 的 LIKE 關鍵字搭配萬用字元,例如: "SF3%",就能快速比對並撈出所有以 SF3 開頭的教室,例如 SF304、SF309、SF310 。

4. 查單一教室資料

@Query("SELECT * FROM classroom_schedules WHERE classroom = :classRoomName")
fun getClassroomDetails(classRoomName: String): Flow<ClassroomSchedule?>

@Query("SELECT * FROM classroom_schedules WHERE classroom = :classroomName LIMIT 1")
suspend fun findByName(classroomName: String): ClassroomSchedule?
  • 技術細節:兩者都查單一教室,但 getClassroomDetails() 回傳 Flow,可以持續觀察資料變化;findByName() 是一次性查詢。

各層之間的關係

RoomRush 裡,Entity、DAO、Repository 各自關係負責如下:

ClassroomSchedule
「定義資料結構」
        │
        │ Entity
        ▼
Room Database
「實際儲存資料」
        ▲
        │
ClassroomScheduleDao
「定義資料庫操作」
        ▲
        │
Repository
「整理、封裝 DAO」
        ▲
        │
ViewModel
「取得畫面需要的資料」

Hermes Agent 幫我檢查出的重點

ClassroomScheduleDao 是 RoomRush 的資料存取物件,負責定義如何操作 classroom_schedules 資料表。

  • getAll() 會取得所有教室課表並以 Flow<List<ClassroomSchedule>> 回傳,讓資料變動時可以被觀察。
  • insert()、insertAll()、update()、delete() 分別負責新增、批次新增、更新與刪除。
  • getSchedulesByBuildingAndFloor() 可以用前綴查某棟某層的教室。
  • getClassroomDetails() 則用於詳細頁取得單一教室資料。

DAO 不處理 UI,也不決定畫面怎麼顯示,它只定義資料庫操作。


這個檔案帶出的維護觀察

DAO 裡確實有一些 查詢方法,但目前查詢頁真正的空教室篩選邏輯,主要還是在 QueryResultViewModel 裡完成。
也就是說,資料是從資料層拿出來的,但「哪些教室算空教室」這個判斷,還是在 ViewModel 裡進行。

實際的查詢流程:

QueryResultViewModel
    ↓
Repository
    ↓
ClassroomScheduleDao
    ↓
Room Database
    ↓
取得 ClassroomSchedule
    ↓
回到 QueryResultViewModel
    ↓
大樓 / 樓層 / 時段篩選
    ↓
判斷是否為 X
    ↓
emptyRooms

這是我原本沒注意到的細節,之後若需要維護的話,可以考慮把查詢邏輯整合在一起。


小結

讀完 ClassroomScheduleDao 後,我開始理解 Room 架構裡 Entity 和 DAO 的分工。

ClassroomSchedule 定義資料表長什麼樣子,而 DAO 則定義 App 可以對這張表做哪些操作。這些操作包含查全部資料、新增、批次匯入、更新、刪除,也包含根據教室名稱查單一教室資料。

這個檔案也讓我注意到一個值得思考的地方:專案裡已經有 DAO 層的查詢方法,但目前查詢空教室的核心邏輯主要仍寫在 QueryResultViewModel 裡。

這不一定是錯,但它提醒我,未來如果要改善維護性,可以思考查詢邏輯究竟應該放在 ViewModel、Repository,還是 DAO 裡。


下一篇預告:為什麼 ViewModel 不該直接碰資料庫?Repository 的角色是什麼?

了解了 DAO 如何操作 classroom_schedules 資料表後,接下來登場的是資料層的統一接口: ClassroomScheduleRepository.kt。

為什麼 ViewModel 不該直接碰資料庫?Repository 又是如何統整資料來源並將資料流(Flow)向上拋給邏輯層?

儘管回頭檢視時,發現當時的分工有些小瑕疵,但依然清楚體現了資料庫封裝的設計意圖;下一篇,我們將拆解這個串聯「資料庫 DAO」與「邏輯 ViewModel」的關鍵橋樑。


上一篇
Day 11 | 一間教室的一週課表,在資料庫裡長什麼樣子?
下一篇
Day 13 | 為什麼 ViewModel 不該直接碰資料庫?Repository 的角色是什麼?
系列文
從 Vibe Coding 到可維護專案:用 Hermes Agent 重讀 RoomRush Android 專題 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言